在C#中有一個強大的monad - IObservable,這個盒子包裝了一個要被觀察的物件,今天先簡介一下基本概念
先觀察IObservable-IObserver這兩個界面還有簡易的範例
public interface IObservable<out T>
{
// 準備讓被觀察者註冊訂閱的方法
IDisposable Subscribe(IObserver<T> observer);
}
public interface IObserver<in T>
{
// 觀察者接收到通知成功要做的事
void OnNext(T value);
// 觀察者接收到通知失敗要做的事
void OnError(Exception error);
// 全部的通知都收到要做的事情,非必要
void OnCompleted();
}
// 實做IObservable與IObserver物件
public class Observable : IObserable<string> { /* todo */ }
public class Observer : IObserver<string> { /* todo */ }
// 建立被觀察的物件,Observable
IObservable<string> observable = new Observable();
// 建立觀察者物件
IObserver<string> observer = new Observer();
// 註冊訂閱
using var subscribe = observable.Subscribe(observer);
// 把方法組合起來
while (Console.ReadLine() is { } s && s != "q")
{
try
{
observer.OnNext(s);
}
catch (Exception e)
{
observer.OnError(e);
}
}
observer.OnCompleted();
IObservable-IObserver
這兩個介面基本上已經把整個觀察者模式定義出來了,只是每次實做都要實做方法的內容,並沒有想像中的好用,索性我們有Rx.net這個套件,大大化簡了這個流程。
是的,Monad又來了。首先要設計一個IObservable實例非常的麻煩,索性Rx.net幫我們預先準備了幾個方法,先從IObservalbe的一些特性開始
IObservable內部包含了觀察值
這不是廢話嗎?不然要觀察什麼,然而既然是觀察值就代表我們可以觀察單個或是多個值,Rx.net幫我們準備了幾個方法來製作IObservable實例
Observable.Return<T>(T value)
: 就是Return,能夠將T的值包裝進ObservableIEnumerable<T>.ToObservable()
: 可以是觀察多個值,IObservable具有IEnumerable的特性,兩者是可以互相轉換的IObservable內部包含了將來值
我們需要觀察的值在當下是未知的,所以
Task<T>.ToObservable()
:Task<T>
內部包含的也是將來值,所以兩者也是可以轉換的Rx.net將訂閱事件化簡,只需要
observable.Subscribe(onNext:x=>/*成功後要做的事情*/)
就可以達到需要結果。
Rx.net還有一些強大的延伸功能,這邊就不特別詳談,明天探討IObservable的monad特性。